﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
using MacomberMapSystem.Common.Database;
using MacomberMapSystem.Common.Serialization;
using System.Xml;
using MacomberMapSystem.Common.Integration.Blackstart;
using MacomberMapSystem.Common.Internals;
using System.IO;
using MacomberMapSystem.Common.CIM.Direct;
using System.Threading;
using System.Data.OleDb;
using System.Data.Common;

namespace MacomberMapSystem.Common.User_Interfaces.Database
{
    /// <summary>
    ///This class offers a UI for editing a blackstart corridor.
    /// </summary>
    public partial class frmBlackstartCorridor : DockContent
    {
        #region Variable declarations
        /// <summary>Our system repository</summary>
        public MM_Repository Repository;

        /// <summary>Our database connection</summary>
        public MM_Database_Connector Db;

        /// <summary>Our collection of models</summary>
        public Dictionary<int, MM_Database_Model> Models;

        /// <summary>The currently-selected model</summary>
        public MM_Database_Model Model = null;

        /// <summary>The active blackstart corridor</summary>
        public MM_Blackstart_Corridor Corridor = null;

        /// <summary>Our audit log</summary>
        public StringBuilder AuditLog = new StringBuilder();
        #endregion

        #region Initialization
        /// <summary>
        /// Initialize our blackstart corridor editor
        /// </summary>
        /// <param name="Repository"></param>
        /// <param name="Models"></param>
        /// <param name="Db"></param>
        public frmBlackstartCorridor(MM_Repository Repository, Dictionary<int, MM_Database_Model> Models, MM_Database_Connector Db)
        {
            InitializeComponent();
            this.Db = Db;
            this.Repository = Repository;
            this.Models = Models;
            foreach (MM_Database_Model Mdl in Models.Values)
                if (!cmbModelCategory.Items.Contains(Mdl.ModelCategory))
                    cmbModelCategory.Items.Add(Mdl.ModelCategory);
            foreach (MM_Blackstart_Corridor Corridor in Repository.Db.Blackstart_Corridors)
                cmbCorridor.Items.Add(Corridor);
            OneLinePreview.EnableDragDrop = true;

        }
        #endregion

        #region Model selection
        /// <summary>
        /// Update our current selection of models
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbModelCategory_SelectedIndexChanged(object sender, EventArgs e)
        {
            cmbModel.Items.Clear();
            SortedDictionary<int, MM_Database_Model> SortedModels = new SortedDictionary<int, MM_Database_Model>();
            foreach (MM_Database_Model Model in this.Models.Values)
                if (Model.ModelCategory == cmbModelCategory.Text)
                    SortedModels.Add(-Model.ID, Model);
            cmbModel.Items.AddRange(SortedModels.Values.ToArray());
        }

        /// <summary>
        /// Refresh our collection of models
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRefresh_Click(object sender, EventArgs e)
        {
            cmbModel.SelectedIndex = -1;
            cmbModel.Items.Clear();
            new MM_Login_Process("Loading substations", Repository.LoadModels).Invoke();


            foreach (MM_Database_Model Mdl in Models.Values)
                if (!cmbModelCategory.Items.Contains(Mdl.ModelCategory))
                    cmbModelCategory.Items.Add(Mdl.ModelCategory);
        }


        /// <summary>
        /// Select a model by date
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSelect_Click(object sender, EventArgs e)
        {
            using (frmSelectModel SelModel = new frmSelectModel(Repository))
                if (SelModel.ShowDialog() == DialogResult.OK)
                {
                    cmbModelCategory.SelectedItem = SelModel.SelectedModel.ModelCategory;
                    cmbModel.SelectedItem = SelModel.SelectedModel;
                }
        }

        /// <summary>
        /// When the user selects a model, make sure it's opened.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbModel_SelectedIndexChanged(object sender, EventArgs e)
        {
            MM_Database_Model Model = cmbModel.SelectedItem as MM_Database_Model;
            if (Model is CIM_DirectModel == false)
            {
                String IndexPath = Path.Combine(Model.FullPath, Model.Name + ".CimIndex");
                if (!File.Exists(IndexPath))
                    MessageBox.Show("Unable to locate the model's CIM Index!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Stop);
                else
                    Model = CIM_DirectModel.OpenModel(Model, Repository, Models, cmbModel);
            }
            if (Model.EnsureOpened())
                this.Model = Model;
        }
        #endregion



        /// <summary>
        /// Save our data to the system
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSave_Click(object sender, EventArgs e)
        {            
            if (Corridor.ID == int.MinValue)
                Corridor.WriteRdb(Repository);
            else
                Corridor.UpdateRdb(Repository);

            using (SaveFileDialog sFd = new SaveFileDialog() { Title = "Save Blackstart corridor information...", Filter="Blackstart corridor file (*.csv)|*.csv", FileName="Blackstart_Corridor_Information.csv" })
            if (sFd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                using (MacomberMapSystem.Common.User_Interfaces.One_Lines.ctlOneLinePreview Preview = new One_Lines.ctlOneLinePreview())
                {
                    using (StreamWriter sW = new StreamWriter(sFd.FileName, false, new UTF8Encoding(false)))
                    {
                        sW.WriteLine("\"Corridor\",\"Target\",\"PriSec\",\"Num\",\"Command\",\"Substation\",\"SubLongName\",\"Element\",\"rdfID\"");
                        foreach (MM_Blackstart_Corridor ThisCorridor in cmbCorridor.Items)
                            foreach (MM_Blackstart_Corridor_Target Target in ThisCorridor.CorridorTargets)
                            {
                                Dictionary<String, MM_Blackstart_Corridor_Element[]> Elems = new Dictionary<string, MM_Blackstart_Corridor_Element[]>();
                                if (Target.Primary != null)
                                    Elems.Add("Primary", Target.Primary);
                                if (Target.Secondary != null)
                                    Elems.Add("Secondary", Target.Secondary);

                                foreach (KeyValuePair<String, MM_Blackstart_Corridor_Element[]> kvp in Elems)
                                    for (int a = 0; a < kvp.Value.Length; a++)
                                        sW.WriteLine("\"{0}\",\"{1}\",\"{2}\",{3},\"{4}\",\"{5}\",\"{6}\",\"{7}\",\"{8}\"", ThisCorridor.Name, Target.Target, kvp.Key, a, kvp.Value[a].Action.ToString(), (kvp.Value[a].Substation == null ? "?" : kvp.Value[a].Substation.Name), (kvp.Value[a].Substation == null ? "?" : kvp.Value[a].Substation.LongName), (kvp.Value[a].AssociatedElement == null ? "?" : kvp.Value[a].AssociatedElement.LineName), (kvp.Value[a].AssociatedElement == null ? "?" : kvp.Value[a].AssociatedElement.rdfID.ToString()));
                            }
                    }

                    //Compute everything
                    for (int a = 0; a < cmbCorridor.Items.Count; a++)
                    {
                        cmbCorridor.SelectedIndex = a;
                        for (int b = 0; b < cmbTarget.Items.Count; b++)
                        {
                            cmbTarget.SelectedIndex = b;
                            for (int c = 0; c < cmbPrimarySecondary.Items.Count; c++)
                                cmbPrimarySecondary.SelectedIndex = c;
                        }
                    }

                    String FileBase = Path.GetDirectoryName(sFd.FileName);
                    foreach (MM_Blackstart_Corridor ThisCorridor in cmbCorridor.Items)
                    {
                        String BaseDirectory = Path.Combine(FileBase, ThisCorridor.Name);
                        if (!Directory.Exists(BaseDirectory))
                            Directory.CreateDirectory(BaseDirectory);
                        foreach (MM_Blackstart_Corridor_Target Target in ThisCorridor.CorridorTargets)
                        {
                            String TargetDirectory = Path.Combine(BaseDirectory, Target.Target.Replace('/', '_').Replace('\n', '_'));
                            if (!Directory.Exists(TargetDirectory))
                                Directory.CreateDirectory(TargetDirectory);
                            Dictionary<String, MM_Blackstart_Corridor_Element[]> Elems = new Dictionary<string, MM_Blackstart_Corridor_Element[]>();
                            if (Target.Primary != null)
                                Elems.Add("Primary", Target.Primary);
                            if (Target.Secondary != null)
                                Elems.Add("Secondary", Target.Secondary);
                             foreach (KeyValuePair<String, MM_Blackstart_Corridor_Element[]> kvp in Elems)
                            {
                                String TargetPriSecDirectory = Path.Combine(TargetDirectory, kvp.Key);
                                if (!Directory.Exists(TargetPriSecDirectory))
                                    Directory.CreateDirectory(TargetPriSecDirectory);
                                foreach (MM_Blackstart_Corridor_Element Elem in kvp.Value)
                                    if (Elem.Substation != null && !File.Exists(Path.Combine(TargetPriSecDirectory, Elem.Substation.Name + ".png")))
                                        using (System.Data.Common.DbCommand dCmd = Db.CreateCommand("SELECT ID FROM MM_DATABASE_ONELINE WHERE RDFID=:0 AND ONELINETYPE=0 AND MODELS LIKE :1", Elem.Substation.rdfID.ToString(), "%," + Model.ID.ToString() + ",%"))
                                        using (System.Data.Common.DbDataReader dRd = dCmd.ExecuteReader())
                                            if (dRd.Read())
                                            {
                                                Bitmap OLImg = Db.LoadOneLineImage(Convert.ToInt32(dRd["ID"]));
                                                MM_Database_OneLine OneLine = Db.LoadOneLine(Convert.ToInt32(dRd["ID"]), Repository);
                                                Preview.AssignOneLine(OneLine, OLImg, Model, Repository);
                                                Preview.BlackstartElements = kvp.Value;
                                                PictureBox picImage = (PictureBox)Preview.GetType().GetField("picImage", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(Preview);
                                                using (Bitmap b = new Bitmap(picImage.Width, picImage.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
                                                {
                                                    picImage.DrawToBitmap(b, new Rectangle(0, 0, b.Width, b.Height));
                                                    using (Graphics g = Graphics.FromImage(b))
                                                    {
                                                        String OutString = String.Format("Corridor {0}\r\nTarget {1}\r\nPRIMARY PATH", Corridor.Name, Target.Target);
                                                        Size TargetSize = Size.Ceiling(g.MeasureString(OutString, this.Font));
                                                        g.FillRectangle(Brushes.DarkOrange, 0, 50, TargetSize.Width, TargetSize.Height);
                                                        g.DrawString(OutString, this.Font, Brushes.White, 2, 50);
                                                    }
                                                    b.Save(Path.Combine(TargetPriSecDirectory, Elem.Substation.Name + ".png"), System.Drawing.Imaging.ImageFormat.Png);
                                                    Application.DoEvents();
                                                }
                                            }
                            }
                        }
                    }
                }
            
        }

        /// <summary>
        /// Create a new corridor
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnNewCorridor_Click(object sender, EventArgs e)
        {
            String CorridorName = null;
            if (MM_Input_Box.InputBox("Please enter the name for the new corridor:", Application.ProductName, ref CorridorName) != DialogResult.OK)
                return;
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml("<?xml version=\"1.0\"?><Blackstart_Corridor Name=\"" + CorridorName + "\"></Blackstart_Corridor>");
            MM_Blackstart_Corridor NewCorridor = new MM_Blackstart_Corridor(xDoc, Model);
            cmbCorridor.Items.Add(NewCorridor);
            cmbCorridor.SelectedItem = NewCorridor;
        }

        private void cmbTarget_Click(object sender, EventArgs e)
        {

        }

        private void cmbTarget_SelectedIndexChanged(object sender, EventArgs e)
        {
            cmbPrimarySecondary.SelectedIndex = -1;
        }

        /// <summary>
        /// Handle the change of primary/secondary corridor information
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbPrimarySecondary_SelectedIndexChanged(object sender, EventArgs e)
        {
            //First, make sure we have a target in place
            String CorridorName = null;
            if (Corridor == null && MM_Input_Box.InputBox("Please enter the name for this corridor", Application.ProductName, ref CorridorName) == DialogResult.OK && !String.IsNullOrEmpty(CorridorName))
            {

                XmlDocument xDoc = new XmlDocument();
                xDoc.LoadXml("<?xml version=\"1.0\"?><Blackstart_Corridor Name=\"" + CorridorName + "\"><Target Name=\"" + cmbTarget.Text + "\"><Primary/><Secondary/></Target></Blackstart_Corridor>");
                Corridor = new MM_Blackstart_Corridor(xDoc, Model);
                cmbTarget.Items.Clear();
                foreach (MM_Blackstart_Corridor_Target Target in Corridor.CorridorTargets)
                    cmbTarget.Items.Add(Target);
                cmbTarget.SelectedItem = Corridor.CorridorTargets[0];
                lvItems.Items.Clear();
            }
            else if (cmbTarget.SelectedItem is MM_Blackstart_Corridor_Target)
            { }
            else if (!String.IsNullOrEmpty(cmbTarget.Text))
            {
                int PriSec = cmbPrimarySecondary.SelectedIndex;
                XmlElement NewTarget = Corridor.Xml.CreateElement("Target");
                NewTarget.Attributes.Append(Corridor.Xml.CreateAttribute("Name")).Value = cmbTarget.Text;
                NewTarget.AppendChild(Corridor.Xml.CreateElement("Primary"));
                NewTarget.AppendChild(Corridor.Xml.CreateElement("Secondary"));
                Corridor.Xml.DocumentElement.AppendChild(NewTarget);
                MM_Blackstart_Corridor_Target Target = new MM_Blackstart_Corridor_Target(NewTarget, Model);
                Corridor.CorridorTargets.Add(Target);
                cmbTarget.Items.Add(Target);
                cmbTarget.SelectedItem = Target;
                cmbPrimarySecondary.SelectedIndex = PriSec;
              
            }
            /* else 
             {
                 MM_Blackstart_Corridor_Target FoundTarget = null;
                 foreach (MM_Blackstart_Corridor_Target Target in Corridor.targets)
                     if (Target.Target == cmbTarget.text
             */
            OneLinePreview.ActiveOneLine = null;
            OneLinePreview.BlackstartElements = null;
            OneLinePreview.AssignOneLine(null, null, null, null);
            UpdateCorridorDisplay();
        }


        /// <summary>
        /// Update our corridor display
        /// </summary>
        private void UpdateCorridorDisplay()
        {
            lvItems.Items.Clear();
            MM_Blackstart_Corridor_Target Target = cmbTarget.SelectedItem as MM_Blackstart_Corridor_Target;
            MM_Blackstart_Corridor_Element[] Elems = null;            
            if (cmbPrimarySecondary.Text == "Primary")
                Elems = Target.Primary;
            else if (cmbPrimarySecondary.Text == "Secondary")
                Elems = Target.Secondary;
            if (Elems != null)
                for (int a = 0; a < Elems.Length; a++)
                {
                    ListViewItem lvI = new ListViewItem((a + 1).ToString("#,##0"));
                    if (Elems[a].Action == MM_Blackstart_Corridor_Element.enumElementActivity.ReachSynchPoint)
                    {
                        lvI.UseItemStyleForSubItems = true;
                        lvI.Font = new System.Drawing.Font(lvI.Font, FontStyle.Bold);
                    }
                    lvI.SubItems.Add(Elems[a].Action.ToString());
                    if (Elems[a].Substation == null)
                    {
                        if (!Elems[a].xConfig.HasAttribute("Substation"))
                            lvI.SubItems.Add("");
                        else
                            lvI.SubItems.Add(Elems[a].xConfig.Attributes["Substation"].Value);
                        lvI.SubItems.Add("");
                    }
                    else
                    {
                        lvI.SubItems.Add(MM_Type_Converter.TitleCase(Elems[a].Substation.Name));
                        lvI.SubItems.Add(MM_Type_Converter.TitleCase(Elems[a].Substation.LongName));
                    }

                    if (Elems[a].AssociatedElement != null)
                        lvI.SubItems.Add(MM_Type_Converter.TitleCase(Elems[a].AssociatedElement.LineName));
                    else
                    {
                        lvI.SubItems.Add(MM_Type_Converter.TitleCase(Elems[a].xConfig.Attributes["Name"].Value));
                        lvI.ForeColor = Color.Red;
                        lvI.UseItemStyleForSubItems = true;
                    }
                    lvI.Tag = Elems[a];
                    lvItems.Items.Add(lvI);
                }
            lvItems.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
        }

        /// <summary>
        /// Handle the click of a menu item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmsItems_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            MM_Blackstart_Corridor_Target Target = cmbTarget.SelectedItem as MM_Blackstart_Corridor_Target;
            List<MM_Blackstart_Corridor_Element> Elems = new List<MM_Blackstart_Corridor_Element>(cmbPrimarySecondary.Text == "Primary" ? Target.Primary : Target.Secondary);


            if (e.ClickedItem.Text == "&Import XML elements from clipboard")
            {

                string InXml = Clipboard.GetText().Replace("\"\"", "\"").Replace("\"\r\n\"", "\r\n").Replace("\r\n\"", "\r\n");
                using (XmlTextReader xRd = new XmlTextReader(InXml, XmlNodeType.Document, null))
                {
                    XmlNode xRead = Target.xConfig.OwnerDocument.ReadNode(xRd);
                    foreach (XmlNode xElem in xRead.ChildNodes)
                        if (xElem is XmlElement)
                            Elems.Add(new MM_Blackstart_Corridor_Element(xElem as XmlElement, Model));
                }
                Target.xConfig[cmbPrimarySecondary.Text].RemoveAll();
                foreach (MM_Blackstart_Corridor_Element Elem in Elems)
                    Target.xConfig[cmbPrimarySecondary.Text].AppendChild(Elem.xConfig);
                if (cmbPrimarySecondary.Text == "Primary")
                    Target.Primary = Elems.ToArray();
                else
                    Target.Secondary = Elems.ToArray();
                UpdateCorridorDisplay();
            }
            else if (e.ClickedItem.Text == "&Delete")
            {
                ListViewItem lvI = cmsItems.Tag as ListViewItem;
                MM_Blackstart_Corridor_Element SelectedElement = lvI.Tag as MM_Blackstart_Corridor_Element;
                if (MessageBox.Show("Are you sure you want to delete the element " + SelectedElement.Text + "?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
                    Elems.RemoveAt(lvI.Index);

                if (cmbPrimarySecondary.Text == "Primary")
                    Target.Primary = Elems.ToArray();
                else
                    Target.Secondary = Elems.ToArray();

                UpdateCorridorDisplay();

            }
            else if (e.ClickedItem.Text == "&Add new element" || e.ClickedItem.Text == "Insert &below" || e.ClickedItem.Text == "&Edit" || e.ClickedItem.Text == "Insert &above")
                using (frmBlackstartElement NewBE = new frmBlackstartElement(Model, e.ClickedItem.Text == "&Edit" ? (cmsItems.Tag as ListViewItem).Tag as MM_Blackstart_Corridor_Element : null, Elems.ToArray()))
                    if (NewBE.ShowDialog(this) == DialogResult.OK)
                    {
                        ListViewItem lvI = cmsItems.Tag as ListViewItem;
                        MM_Blackstart_Corridor_Element SelectedElement = null;
                        if (lvI != null)
                            SelectedElement = lvI.Tag as MM_Blackstart_Corridor_Element;
                        if (e.ClickedItem.Text == "&Edit")
                        {
                            AuditLog.AppendLine(String.Format("{0}.{1} #{2} {3}.{4} was replaced with {5}.{6}.", Corridor.Name, (cmbTarget.SelectedItem as MM_Blackstart_Corridor_Target).Target + "/" + cmbPrimarySecondary.Text, lvI.Index + 1, SelectedElement.Substation == null ? SelectedElement.xConfig.Attributes["Substation"].Name : MM_Type_Converter.TitleCase(SelectedElement.Substation.Name), SelectedElement.xConfig.Attributes["Name"].Value, MM_Type_Converter.TitleCase(NewBE.Substation.Name), NewBE.SelectedElement.LineName));
                            SelectedElement.AssignComponents(NewBE.Action, NewBE.Substation, NewBE.SelectedElement);
                        }
                        else if (e.ClickedItem.Text == "Insert &below")
                        {
                            AuditLog.AppendLine(String.Format("{0}.{1} {3}.{4} was inserted to #{2}.", Corridor.Name, (cmbTarget.SelectedItem as MM_Blackstart_Corridor_Target).Target + "/" + cmbPrimarySecondary.Text, lvI.Index + 2, NewBE.Substation, NewBE.SelectedElement));
                            Elems.Insert(lvI.Index + 1, new MM_Blackstart_Corridor_Element(NewBE.Action, NewBE.Substation, NewBE.SelectedElement, Target.xConfig[cmbPrimarySecondary.Text], SelectedElement.xConfig, false));
                        }
                        else if (e.ClickedItem.Text == "Insert &above")
                        {
                            AuditLog.AppendLine(String.Format("{0}.{1} {3}.{4} was inserted to #{2}.", Corridor.Name, (cmbTarget.SelectedItem as MM_Blackstart_Corridor_Target).Target + "/" + cmbPrimarySecondary.Text, lvI.Index + 1, NewBE.Substation, NewBE.SelectedElement));
                            Elems.Insert(lvI.Index, new MM_Blackstart_Corridor_Element(NewBE.Action, NewBE.Substation, NewBE.SelectedElement, Target.xConfig[cmbPrimarySecondary.Text], SelectedElement.xConfig, true));
                        }
                        else if (e.ClickedItem.Text == "&Add new element")
                        {
                            Elems.Add(new MM_Blackstart_Corridor_Element(NewBE.Action, NewBE.Substation, NewBE.SelectedElement, Target.xConfig[cmbPrimarySecondary.Text], null, false));
                            AuditLog.AppendLine(String.Format("{0}.{1} {3}.{4} was added to #{2}.", Corridor.Name, (cmbTarget.SelectedItem as MM_Blackstart_Corridor_Target).Target + "/" + cmbPrimarySecondary.Text, Elems.Count + 1, NewBE.Substation, NewBE.SelectedElement));
                        }
                        if (cmbPrimarySecondary.Text == "Primary")
                            Target.Primary = Elems.ToArray();
                        else
                            Target.Secondary = Elems.ToArray();
                        UpdateCorridorDisplay();
                    }
            OneLinePreview.BlackstartElements = Elems.ToArray();
            OneLinePreview.Refresh();
        }

        private void cmsItems_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
        }

        /// <summary>
        /// Handle an update in selected listview item
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lvItems_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lvItems.SelectedItems.Count != 1)
                return;// OneLinePreview.AssignOneLine(null, null, null, Repository);

            MM_Blackstart_Corridor_Element Elem = lvItems.SelectedItems[0].Tag as MM_Blackstart_Corridor_Element;
            if (Elem.Substation != null && (OneLinePreview.ActiveOneLine == null || !OneLinePreview.ActiveOneLine.rdfID.Equals(Elem.Substation.rdfID)))
                using (System.Data.Common.DbCommand dCmd = Db.CreateCommand("SELECT ID FROM MM_DATABASE_ONELINE WHERE RDFID=:0 AND ONELINETYPE=0 AND MODELS LIKE :1", Elem.Substation.rdfID.ToString(), "%," + Model.ID.ToString() + ",%"))
                using (System.Data.Common.DbDataReader dRd = dCmd.ExecuteReader())
                    if (dRd.Read())
                    {
                        Bitmap OLImg = Db.LoadOneLineImage(Convert.ToInt32(dRd["ID"]));
                        MM_Database_OneLine OneLine = Db.LoadOneLine(Convert.ToInt32(dRd["ID"]), Repository);
                        OneLinePreview.AssignOneLine(OneLine, OLImg, Model, Repository);
              
                        MM_Blackstart_Corridor_Target Target = cmbTarget.SelectedItem as MM_Blackstart_Corridor_Target;
                        OneLinePreview.BlackstartElements = cmbPrimarySecondary.Text == "Primary" ? Target.Primary : Target.Secondary;
                    }

            TreeView tvOneLine = (TreeView)OneLinePreview.GetType().GetField("tvOneLine", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(OneLinePreview);
            TreeNode FoundNode;
            if (Elem.AssociatedElement == null)
                tvOneLine.SelectedNode = null;
            else if (OneLinePreview.Elements.TryGetValue(Elem.AssociatedElement.rdfID, out FoundNode))
            {
                tvOneLine.SelectedNode = FoundNode;
                Panel pnlPicture = (Panel)OneLinePreview.GetType().GetField("pnlPicture", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(OneLinePreview);
                pnlPicture.AutoScrollPosition = ((KeyValuePair<XmlElement, Rectangle>)FoundNode.Tag).Value.Location;
            }
        }

        private void lvItems_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right && lvItems.HitTest(e.Location).Item == null)
            {
                cmsItems.Items.Clear();
                cmsItems.Items.Add("&Add new element");
                cmsItems.Items.Add("&Import XML elements from clipboard");
                cmsItems.Show((sender as Control), e.Location);
            }
        }

        /// <summary>
        /// Hanle the right-click of a menu item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lvItems_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Right)
                return;
            ListViewHitTestInfo hti = lvItems.HitTest(e.Location);
            cmsItems.Items.Clear();

            if (hti.Item != null)
            {
                if ((hti.Item.Tag as MM_Blackstart_Corridor_Element).Substation != null)
                    cmsItems.Items.Add("Substation: " + (hti.Item.Tag as MM_Blackstart_Corridor_Element).Substation.LongName + " (" + (hti.Item.Tag as MM_Blackstart_Corridor_Element).Substation.Name + ")");
                if ((hti.Item.Tag as MM_Blackstart_Corridor_Element).AssociatedElement != null)
                    (hti.Item.Tag as MM_Blackstart_Corridor_Element).AssociatedElement.WriteMenuElement(cmsItems.Items, cmsItems);
                else
                    cmsItems.Items.Add("Element: " + (hti.Item.Tag as MM_Blackstart_Corridor_Element).xConfig.Attributes["Name"].Value);

                cmsItems.Items.Add("Line: " + (hti.Item.Tag as MM_Blackstart_Corridor_Element).LineNumber.ToString());
                cmsItems.Items.Add("Text: " + (hti.Item.Tag as MM_Blackstart_Corridor_Element).Text.ToString());

                cmsItems.Items.Add("-");
                cmsItems.Items.Add("Insert &above");
                cmsItems.Items.Add("Insert &below");
                cmsItems.Items.Add("&Edit");
                cmsItems.Items.Add("&Delete");
                cmsItems.Tag = hti.Item;
            }
            else
                cmsItems.Items.Add("&Add new element");
            cmsItems.Show((sender as Control), e.Location);
        }


        /// <summary>
        /// Handle a drag/drop event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lvItems_DragDrop(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(typeof(XmlElement)))
                return;
            XmlElement AssociatedElement = e.Data.GetData(typeof(XmlElement)) as XmlElement;
            ListViewHitTestInfo hti = lvItems.HitTest(lvItems.PointToClient(new Point(e.X, e.Y)));
            if (lvItems.InsertionMark.Index != -1 && (Control.ModifierKeys & Keys.Control) == Keys.Control)
            {
                MM_Blackstart_Corridor_Target Target = cmbTarget.SelectedItem as MM_Blackstart_Corridor_Target;
                List<MM_Blackstart_Corridor_Element> Elems = new List<MM_Blackstart_Corridor_Element>(cmbPrimarySecondary.Text == "Primary" ? Target.Primary : Target.Secondary);
                MM_Blackstart_Corridor_Element Elem=null;
                MM_Blackstart_Corridor_Element SiblingElem = hti.Item.Tag as MM_Blackstart_Corridor_Element;

                MacomberMapSystem.Common.CIM.CIM_Element NewElem = Model.FromRdfID(AssociatedElement.Attributes["rdfID"].Value);

                

                if (AssociatedElement.Name == "Breaker")
                    Elem = new MM_Blackstart_Corridor_Element(MM_Blackstart_Corridor_Element.enumElementActivity.Close_Breaker, NewElem.Substation, NewElem, Target.xConfig[cmbPrimarySecondary.Text], SiblingElem.xConfig, !lvItems.InsertionMark.AppearsAfterItem);
                else if (AssociatedElement.Name=="Unit")
                    Elem = new MM_Blackstart_Corridor_Element(MM_Blackstart_Corridor_Element.enumElementActivity.EnergizeUnit, NewElem.Substation, NewElem, Target.xConfig[cmbPrimarySecondary.Text], SiblingElem.xConfig, !lvItems.InsertionMark.AppearsAfterItem);
                else if (AssociatedElement.Name=="Line")
                    Elem = new MM_Blackstart_Corridor_Element(MM_Blackstart_Corridor_Element.enumElementActivity.EnergizeLine, NewElem.Substation, NewElem, Target.xConfig[cmbPrimarySecondary.Text], SiblingElem.xConfig, !lvItems.InsertionMark.AppearsAfterItem);


                if (lvItems.InsertionMark.AppearsAfterItem)
                    Elems.Insert(lvItems.InsertionMark.Index+1, Elem);
                else
                    Elems.Insert(lvItems.InsertionMark.Index, Elem);
                if (cmbPrimarySecondary.Text == "Primary")
                    Target.Primary = Elems.ToArray();
                else
                    Target.Secondary = Elems.ToArray();
                UpdateCorridorDisplay();
                OneLinePreview.Refresh();

            }
            else if (hti.Item != null)
            {
                MM_Blackstart_Corridor_Element Elem = hti.Item.Tag as MM_Blackstart_Corridor_Element;


                //Find the current substation we're in.
                MacomberMapSystem.Common.CIM.CIM_Element NewSub = null;
                if (AssociatedElement.OwnerDocument.DocumentElement.HasAttribute("rdfID") && !String.IsNullOrEmpty(AssociatedElement.OwnerDocument.DocumentElement.Attributes["rdfID"].Value))
                    NewSub = Model.FromRdfID(AssociatedElement.OwnerDocument.DocumentElement.Attributes["rdfID"].Value);
                else
                    NewSub = Model.FromTEID(Convert.ToUInt64(AssociatedElement.OwnerDocument.DocumentElement.Attributes["BaseElement.TEID"].Value));
                MacomberMapSystem.Common.CIM.CIM_Element NewElem = Model.FromRdfID(AssociatedElement.Attributes["rdfID"].Value);
                AuditLog.AppendLine(String.Format("{0}.{1} #{2} {3}.{4} was replaced with {5}.{6}.", Corridor.Name, (cmbTarget.SelectedItem as MM_Blackstart_Corridor_Target).Target + "/" + cmbPrimarySecondary.Text, hti.Item.Index + 1, Elem.Substation == null ? Elem.xConfig.Attributes["Substation"].Name : MM_Type_Converter.TitleCase(Elem.Substation.Name), Elem.xConfig.Attributes["Name"].Value, MM_Type_Converter.TitleCase(NewSub.Name), NewElem.LineName));
                Elem.AssignComponents(Elem.Action, NewSub, NewElem);
                hti.Item.SubItems[1].Text = Elem.Action.ToString();
                hti.Item.SubItems[2].Text = MM_Type_Converter.TitleCase(NewSub.Name);
                hti.Item.SubItems[3].Text = MM_Type_Converter.TitleCase(NewSub.LongName);
                hti.Item.SubItems[4].Text = Elem.AssociatedElement.LineName;
                hti.Item.ForeColor = lvItems.ForeColor;
                OneLinePreview.Refresh();
            }
            lvItems.InsertionMark.Index = -1;
        }

        /// <summary>
        /// Handle the enter of dragged item into the listview.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lvItems_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(XmlElement)))
                e.Effect = DragDropEffects.All;
        }

        /// <summary>
        /// When we drag/move, highlight our target element
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lvItems_DragOver(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(XmlElement)))
            {
                Point ItemPoint = lvItems.PointToClient(new Point(e.X, e.Y));
                int targetIndex = lvItems.InsertionMark.NearestIndex(ItemPoint);
                if (targetIndex > -1)
                {
                    Rectangle itemBounds = lvItems.GetItemRect(targetIndex);
                    if (ItemPoint.X > itemBounds.Left + (itemBounds.Width / 2))
                        lvItems.InsertionMark.AppearsAfterItem = true;
                    else
                        lvItems.InsertionMark.AppearsAfterItem = false;
                }
                lvItems.InsertionMark.Index = targetIndex;
            }
        }

        /// <summary>
        /// When the drag stops, hide our insertion mark.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lvItems_DragLeave(object sender, EventArgs e)
        {
            lvItems.InsertionMark.Index = -1;
        }

        /// <summary>
        /// When a corridor is updated, retrieve it
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbCorridor_SelectedIndexChanged(object sender, EventArgs e)
        {
            Corridor = cmbCorridor.SelectedItem as MM_Blackstart_Corridor;
            cmbTarget.Items.Clear();
            cmbTarget.Items.AddRange(Corridor.CorridorTargets.ToArray());
            cmbTarget.Text = "";
            cmbTarget.SelectedIndex = -1;
            cmbPrimarySecondary.SelectedIndex = -1;
            lvItems.Items.Clear();

            //Merge our corridor information
            Corridor.AssignModel(Model);
            if (cmbTarget.Items.Count > 0)
            {
                cmbTarget.SelectedIndex = 0;
                cmbPrimarySecondary.SelectedIndex = 0;
            }
        }

        /// <summary>
        /// Handle the note button click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnNotes_Click(object sender, EventArgs e)
        {
            MM_Blackstart_Corridor_Target Target = cmbTarget.SelectedItem as MM_Blackstart_Corridor_Target;
            if (Target == null)
                return;
            String TargetDescription = Target.Description;
            if (MM_Input_Box.InputBox("Please enter notes for corridor " + Target.Target + ":", Application.ProductName, ref TargetDescription) == DialogResult.OK)
                Target.Description = TargetDescription;
        }

        /// <summary>
        /// Export our collection of changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnExportChanges_Click(object sender, EventArgs e)
        {
            using (SaveFileDialog sFd = new SaveFileDialog())
            {
                sFd.Title = "Select a file name for writing out the blackstart corridor audit log";
                sFd.Filter = "Text file (*.txt)|*.txt";
                sFd.FileName = "Blackstart_Corridor_Audit_" + DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss") + ".txt";
                if (sFd.ShowDialog() == DialogResult.OK)
                    using (StreamWriter sW = new StreamWriter(sFd.FileName))
                        sW.WriteLine(AuditLog.ToString());
            }
        }

        /// <summary>
        /// Import from Excel, and create our document
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnImport_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog oFd = new OpenFileDialog())
            {
                oFd.Title = "Open blackstart corridor restoration worksheet";
                oFd.Filter = "Excel 2007 or later spreadsheet (*.xlsx)|*.xlsx";
                if (oFd.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                    return;

                using (DbCommand dCmd = Repository.Db.CreateCommand("DELETE FROM MM_BLACKSTART_CORRIDOR"))
                    dCmd.ExecuteNonQuery();

                //Connect to our Excel database
                using (OleDbConnection oConn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + oFd.FileName + ";Extended Properties=\"Excel 12.0 Xml;HDR=NO\";"))
                {
                    oConn.Open();
                    foreach (DataRow TableRow in oConn.GetSchema("Tables").Rows)
                        if (!TableRow["Table_Name"].ToString().Contains("Changes"))
                    {

                        XmlDocument xBlackstart = new XmlDocument();
                        XmlNode xPriSec = null;

                        xBlackstart.AppendChild(xBlackstart.CreateElement("Blackstart_Corridor"));
                        String CorridorName = TableRow["Table_Name"].ToString().Trim('\'').TrimEnd('$');
                        xBlackstart.DocumentElement.Attributes.Append(xBlackstart.CreateAttribute("Name")).Value = CorridorName;
                        int LineNumber = 0;
                        using (OleDbCommand oCmd = new OleDbCommand("SELECT * FROM [" + TableRow["Table_Name"] + "]", oConn))
                        using (OleDbDataReader oRd = oCmd.ExecuteReader())
                            while (oRd.Read())
                            {
                                LineNumber++;
                                if (oRd["F1"].ToString() == "EMS" && oRd["F2"].ToString() == "Full Name")
                                {
                                    string TargetName = oRd["F4"].ToString();
                                    if (TargetName.Contains('('))
                                        TargetName = TargetName.Substring(0, TargetName.IndexOf('(') - 1).Trim();

                                    //Now, find our target
                                    XmlNode xTarget = xBlackstart.SelectSingleNode("Blackstart/Target[@Name='" + TargetName + "']");
                                    if (xTarget == null)
                                    {
                                        xTarget = xBlackstart.CreateElement("Target");
                                        xTarget.Attributes.Append(xBlackstart.CreateAttribute("Name")).Value = TargetName;
                                        xBlackstart.DocumentElement.AppendChild(xTarget);
                                    }

                                    //Now, assign primary or secondary status
                                    if (oRd["F4"].ToString().IndexOf("(Secondary", StringComparison.CurrentCultureIgnoreCase) != -1)
                                        xTarget.AppendChild(xPriSec = xBlackstart.CreateElement("Secondary"));
                                    else
                                        xTarget.AppendChild(xPriSec = xBlackstart.CreateElement("Primary"));
                                }
                                else if (!String.IsNullOrEmpty(oRd["F1"].ToString()))
                                {
                                    String Action = oRd["F4"].ToString();
                                    String Substation = oRd["F1"].ToString();
                                    String TDSP = oRd["F3"].ToString();
                                    String[] splAction = Action.Split(new char[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries);

                                    //Handle our logic here
                                    if (Action.StartsWith("Energize BS unit", StringComparison.CurrentCultureIgnoreCase))
                                    {
                                        for (int a = 1; a < splAction.Length; a++)
                                            if (!String.IsNullOrWhiteSpace(splAction[a]))
                                                AddBlackstartStep(xPriSec, MM_Blackstart_Corridor_Element.enumElementActivity.EnergizeUnit, Substation, TDSP, splAction[a], "Unit", Action, LineNumber);
                                    }
                                    else if (Action.StartsWith("Close Breaker", StringComparison.CurrentCultureIgnoreCase))
                                        AddBlackstartStep(xPriSec, MM_Blackstart_Corridor_Element.enumElementActivity.Close_Breaker, Substation, TDSP, Action.Substring("Close Breaker ".Length).Trim().Split(' ')[0], "Breaker", Action, LineNumber);
                                    else if (Action.StartsWith("Energize Line", StringComparison.CurrentCultureIgnoreCase))
                                        AddBlackstartStep(xPriSec, MM_Blackstart_Corridor_Element.enumElementActivity.EnergizeLine, Substation, TDSP, splAction[1], "Line", Action, LineNumber);
                                    else if (Action.StartsWith("Reach Syn. Point"))
                                    {
                                        String[] TargetWords = Action.Substring("Reach Syn. Point ".Length).Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                                        AddBlackstartStep(xPriSec, MM_Blackstart_Corridor_Element.enumElementActivity.ReachSynchPoint, Substation, TDSP, TargetWords[1], TargetWords[0], Action, LineNumber);
                                    }
                                    else if (Action.StartsWith("Close Switch"))
                                        AddBlackstartStep(xPriSec, MM_Blackstart_Corridor_Element.enumElementActivity.Close_Switch, Substation, TDSP, Action.Substring("Close Switch ".Length).Trim(), "Switch", Action, LineNumber);
                                    else
                                    {
                                    }

                                }


                            }

                        //Write out our XML file
                        String FilePath = Path.Combine(Path.GetDirectoryName(oFd.FileName), CorridorName + ".xml");
                        using (XmlTextWriter xW = new XmlTextWriter(FilePath, new UTF8Encoding(false)) { Formatting = Formatting.Indented })
                            xBlackstart.WriteTo(xW);
                        using (DbCommand dCmd = Repository.Db.CreateCommand("INSERT INTO MM_BLACKSTART_CORRIDOR (ID,NAME,XML) VALUES (SEQ_MM_BLACKSTART_CORRIDOR.NEXTVAL, :0, :1)", CorridorName, File.ReadAllText(FilePath)))
                            dCmd.ExecuteNonQuery();
                        
                    }
                }

            }
            MessageBox.Show("Completed blackstart corridor import", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        /// <summary>
        /// Add a step to our blackstart corridor
        /// </summary>
        /// <param name="xPriSec"></param>
        /// <param name="Activity"></param>
        /// <param name="Substation"></param>
        /// <param name="ElementName"></param>
        /// <param name="ElementType"></param>
        /// <param name="TDSP"></param>
        /// <param name="Action"></param>
        /// <param name="LineNumber"></param>
        private void AddBlackstartStep(XmlNode xPriSec, MM_Blackstart_Corridor_Element.enumElementActivity Activity, String Substation, String TDSP, String ElementName, String ElementType, String Action, int LineNumber)
        {
            XmlElement xStep = xPriSec.OwnerDocument.CreateElement(ElementType);
            xStep.Attributes.Append(xPriSec.OwnerDocument.CreateAttribute("Action")).Value = Activity.ToString();
            xStep.Attributes.Append(xPriSec.OwnerDocument.CreateAttribute("Substation")).Value = Substation;
            xStep.Attributes.Append(xPriSec.OwnerDocument.CreateAttribute("Name")).Value = ElementName;
            xStep.Attributes.Append(xPriSec.OwnerDocument.CreateAttribute("TDSP")).Value = TDSP;
            xStep.Attributes.Append(xPriSec.OwnerDocument.CreateAttribute("Text")).Value = Action;
            xStep.Attributes.Append(xPriSec.OwnerDocument.CreateAttribute("LineNumber")).Value = LineNumber.ToString();
            xPriSec.AppendChild(xStep);
        }


    }
}